﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.Win32;
using weBoard.Properties;
using Image = System.Windows.Controls.Image;
using Point = System.Windows.Point;

namespace weBoard
{
    /// <summary>
    /// Interaction logic for mainWnd.xaml
    /// </summary>
    public partial class mainWnd
    {
               
        public mainWnd()
        {
            InitializeComponent();
        }

        #region GUI independent functions
        //-----------------------------------------------------------------
        //non-interactive logic below
        //-----------------------------------------------------------------

        /// <summary>
        /// determines item to select
        /// </summary>
        /// <returns>Index of UIElement in Canvas</returns>
        private static int SearchItemAtCoord(Canvas canv, Point pt)
        {
            if (null == canv)
                return -1;
            var test = VisualTreeHelper.HitTest(canv, pt);
            if (null != test)
            {
                if (!Equals(test.VisualHit, canv))
                {
                    var uid = ((UIElement)test.VisualHit).Uid;
                    foreach (UIElement el in canv.Children)
                        if (Equals(el.Uid, uid))
                            return canv.Children.IndexOf(el);
                }
                return -1;
            }
            return -1;
        }

        /// <summary>
        /// Draws selection border for selected object
        /// </summary>
        private bool Select()
        {
            return Drawbot.Select(SearchItemAtCoord(Draw, _position), _selectionColor, true);
        }

        /// <summary>
        /// Deselects currently selected object and drops selection state
        /// </summary>
        private void Deselect()
        {
            Drawbot.Deselect();
        }

        /// <summary>
        /// Redo routine
        /// </summary>
        private void Redo()
        {
            Drawbot.Redo();
        }

        /// <summary>
        /// Undo routine
        /// </summary>
        private void Undo()
        {
            Drawbot.Undo();
        }

        /// <summary>
        /// Erases selected object
        /// </summary>
        private void ExecDeleteSelected()
        {
            Drawbot.DeleteSelectedAction();
            var act = Drawbot.GetLastAction();
            if (act != null && _client != null)
            _client.SendActionMsg(act);
        }

        /// <summary>
        /// Changes size of selected object and it's selection border
        /// </summary>
        private void ExecResizeSelection()
        {
            Drawbot.ResizeSelectionAction(_currentSize, _selectionColor, true);
            var act = Drawbot.GetLastAction();
            if (act != null && _client != null)
                _client.SendActionMsg(act);
        }

        /// <summary>
        /// Moves currently selected object and it's selection bounds
        /// </summary>
        private void ExecMoveSelectionObjects(bool finalized)
        {
            Drawbot.MoveSelectionAction(_position, _selectionColor, finalized);
            var act = Drawbot.GetLastAction();
            if (act != null && _client != null && finalized)
                _client.SendActionMsg(act);
        }

        /// <summary>
        /// Just changes color of selected object
        /// </summary>
        private void ExecSetObjectColors()
        {
            Drawbot.RecolorSelectedAction(_currentColor, true);
            var act = Drawbot.GetLastAction();
            if (act != null && _client != null)
                _client.SendActionMsg(act);
        }

        /// <summary>
        /// Creates point
        /// </summary>
        private void ExecPointCreation()
        {
            var act = new weBoardAction
            {
                Uid = Guid.NewGuid().ToString(),
                Was = null,
                Act = weActType.Create,
                Record = true,
                Now = new weBoardState
                {
                    Fill = new SolidColorBrush(_currentColor),
                    Width = _currentSize,
                    Height = _currentSize,
                    CoordsA = new Point(_position.X - _currentSize / 2, _position.Y - _currentSize / 2)
                },
                Object = weObjType.ObjPoint
            };
            Drawbot.Action(act);
            var lastAct = Drawbot.GetLastAction();
            if (lastAct != null && _client != null)
                _client.SendActionMsg(lastAct);
        }

        /// <summary>
        /// This for two point objects (like ellipse, rect, line)
        /// </summary>
        /// <param name="mode">Object to create</param>
        private void Exec2PtObjectsCreation(eCurSel mode)
        {
            switch (mode)
            {
                case eCurSel.DrawLine:
                    _a = new weBoardAction
                    {
                        Was = null,
                        Uid = Guid.NewGuid().ToString(),
                        Act = weActType.Create,
                        Record = false,
                        Object = weObjType.ObjLine,
                        Now =
                            new weBoardState
                            {
                                Fill = new SolidColorBrush(_currentColor),
                                CoordsA = _position,
                                CoordsB = new Point(_position.X + 100, _position.Y + 100),
                                Width = _currentSize
                            }
                    };
                    break;
                case eCurSel.DrawRect:

                    break;
                case eCurSel.DrawEllipse:

                    break;
            }
            Drawbot.Action(_a);
            var lastAct = Drawbot.GetLastAction();
            if (lastAct != null && _client != null)
                _client.SendActionMsg(lastAct);
        }
        #endregion GUI independent functions

        #region Additional GUI logic to reduce functions' sizes and code dups
        //-----------------------------------------------------------------
        //Additional logic connected with GUI and events below
        //-----------------------------------------------------------------

        /// <summary>
        /// Prepares images for using
        /// </summary>
        private void InitImages()
        {
            if (!_imgsPrepared)
            {

                _modeMedia = new List<modeMediaData>();
                var node = new modeMediaData
                {
                    Cursor = weBoardRoutines.GetCursor("arrowPt"),
                    ActiveBmp = weBoardRoutines.GetImage("Resources/point_active.png"),
                    InactiveBmp = weBoardRoutines.GetImage("Resources/point.png")
                };
                _modeMedia.Add(node);

                node = new modeMediaData
                {
                    Cursor = weBoardRoutines.GetCursor("arrowLine"),
                    ActiveBmp = weBoardRoutines.GetImage("Resources/line_active.png"),
                    InactiveBmp = weBoardRoutines.GetImage("Resources/line.png")
                };
                _modeMedia.Add(node);

                node = new modeMediaData
                {
                    Cursor = weBoardRoutines.GetCursor("arrowRect"),
                    ActiveBmp = weBoardRoutines.GetImage("Resources/rectangle_active.png"),
                    InactiveBmp = weBoardRoutines.GetImage("Resources/rectangle.png")
                };
                _modeMedia.Add(node);

                node = new modeMediaData
                {
                    Cursor = weBoardRoutines.GetCursor("arrowEllipse"),
                    ActiveBmp = weBoardRoutines.GetImage("Resources/ellipse_active.png"),
                    InactiveBmp = weBoardRoutines.GetImage("Resources/ellipse.png")
                };
                _modeMedia.Add(node);

                node = new modeMediaData
                {
                    Cursor = weBoardRoutines.GetCursor("arrowPolygon"),
                    ActiveBmp = weBoardRoutines.GetImage("Resources/polygon_active.png"),
                    InactiveBmp = weBoardRoutines.GetImage("Resources/polygon.png")
                };
                _modeMedia.Add(node);

                node = new modeMediaData
                {
                    Cursor = weBoardRoutines.GetCursor("arrowPath"),
                    ActiveBmp = weBoardRoutines.GetImage("Resources/path_active.png"),
                    InactiveBmp = weBoardRoutines.GetImage("Resources/path.png")
                };
                _modeMedia.Add(node);

                node = new modeMediaData
                {
                    Cursor = weBoardRoutines.GetCursor("arrowPolyline"),
                    ActiveBmp = weBoardRoutines.GetImage("Resources/polyline_active.png"),
                    InactiveBmp = weBoardRoutines.GetImage("Resources/polyline.png")
                };
                _modeMedia.Add(node);

                node = new modeMediaData
                {
                    Cursor = weBoardRoutines.GetCursor("arrow"),
                    ActiveBmp = weBoardRoutines.GetImage("Resources/cursor_active.png"),
                    InactiveBmp = weBoardRoutines.GetImage("Resources/cursor.png")
                };
                _modeMedia.Add(node);

                _imgsPrepared = true;
            }
        }

        /// <summary>
        /// Draws text with coords of mouse pointer inside drawing area
        /// </summary>
        private void DrawCoords()
        {
            LblCoordsX.Content = "X:" + ((int)_position.X).ToString(CultureInfo.InvariantCulture);
            LblCoordsY.Content = "Y:" + ((int)_position.Y).ToString(CultureInfo.InvariantCulture);
        }

        /// <summary>
        /// Saves drawing to file
        /// </summary>
        /// <param name="canvas">Canvas to save</param>
        /// <param name="filename">Filename to save</param>
        private void SaveCanvas(Canvas canvas, string filename)
        {
            if (canvas != null)
            {
                //"magics" 56, 5 and 55 below are present here cause of 
                //hellish xaml layout designer...or i'm just a stupid guy
                //Target was to get 800x600 _right_cropped_ image
                var renderIt = new RenderTargetBitmap((int)canvas.ActualWidth + 56,
                    (int)canvas.ActualHeight + 6, 96d, 96d, PixelFormats.Pbgra32);
                renderIt.Render(canvas);
                var encoder = new PngBitmapEncoder();
                var crop = new CroppedBitmap(renderIt, new Int32Rect(54, 6, 800, 600));
                encoder.Frames.Add(BitmapFrame.Create(crop));
                using (var file = File.Create(filename))
                    encoder.Save(file);
                System.Diagnostics.Process.Start(filename);
            }
        }

        /// <summary>
        /// Drops misc. flags
        /// </summary>
        private void ResetDrawingState()
        {
            _canMove = false;
            _creation = false;
            _firstMove = 0;
            Drawbot.SetDelta(_position, false);
        }

        /// <summary>
        /// Adds new color to "Last colors" palette
        /// </summary>
        /// <param name="clr">New color</param>
        private void ShiftLastColorsPalette(Color clr)
        {
            if (clr == ((SolidColorBrush) RectL5.Background).Color)
                return;
            RectL1.Background = RectL2.Background;
            RectL2.Background = RectL3.Background;
            RectL3.Background = RectL4.Background;
            RectL4.Background = RectL5.Background;
            RectL5.Background = new SolidColorBrush(clr);
        }

        /// <summary>
        /// Sets and draws selected colors
        /// </summary>
        /// <param name="img">Image used as source to get color</param>
        private void SetNewColors(Image img, bool shift)
        {
            var clr = weBoardRoutines.GetColorAtMousePoint(img);
            if (shift)
                ShiftLastColorsPalette(clr);
            if (!_isBackColor)
            {
                _currentColor = clr;
                LblForeColor.Background = new SolidColorBrush(_currentColor);
            }
            else
            {
                _backgroundColor = clr;
                _selectionColor = weBoardRoutines.GetMedInvColor(_backgroundColor, _currentColor);
                Drawbot.Reselect(_selectionColor);
                LblBackColor.Background = new SolidColorBrush(_backgroundColor);
                Draw.Background = LblBackColor.Background;
            }
        }

        /// <summary>
        /// Shows or hides Size Buttons
        /// </summary>
        /// <param name="show">Show or hide</param>
        private void ShowButtons(String uid, bool show)
        {
            for (var i = 0; i < VisualTreeHelper.GetChildrenCount(MainGrid); i++)
            {
                var child = VisualTreeHelper.GetChild(MainGrid, i);
                if (child.GetType() == typeof(Button))
                    if (((Button)child).Uid == uid)
                        ((Button)child).Visibility = show ? Visibility.Visible : Visibility.Hidden;
            }
        }

        /// <summary>
        /// Hides all tool windows
        /// </summary>
        /// <returns>Were somtheing cancelled or not</returns>
        private bool HideTools()
        {
            var result = false;
            if (_sizeSelStarted)
            {
                BtnSize_Click(null, new RoutedEventArgs());
                result = true;
            }
            if (_toolSelStarted)
            {
                BtnTool_Click(null, new RoutedEventArgs());
                result = true;
            }
            if (_isPalVisible)
            {
                BtnPalette_Click(null, new RoutedEventArgs());
                result = true;
            }
            return result;
        }

        /// <summary>
        /// Process keyboard events
        /// </summary>
        /// <param name="kbd">Transferred KeyEventargs</param>
        private void ProcessKeyboard(KeyEventArgs kbd)
        {
            if (kbd.Key == Key.Escape)
            {
                kbd.Handled = HideTools();
                if (kbd.Handled)
                    return;
                if (MessageBox.Show("Are you sure?", "Close app", MessageBoxButton.YesNo,
                    MessageBoxImage.Question) == MessageBoxResult.Yes)
                    Close();
            }

            if (kbd.Key == Key.Delete && _nowSelectedMode == eCurSel.Select)
                ExecDeleteSelected();

            var key = kbd.Key;
            if (Keyboard.Modifiers == ModifierKeys.Control)
            {
                if (key == Key.Z)
                    Undo();
                if (key == Key.Y)
                    Redo();
                if (key == Key.S)
                    BtnSave_Click(this, kbd);
                if (key == Key.M)
                    BtnSize_Click(this, kbd);
                if (key == Key.A)
                    BtnSelect_Click(this, kbd);
                if (key == Key.D)
                    BtnTool_Click(this, kbd);
            }
        }

        /// <summary>
        /// Sets size and updates size of selected object
        /// </summary>
        /// <param name="size">Desired size</param>
        private void SetSize(int size)
        {
            if (size > NSizes)
                _szIdx = NSizes - 1;
            else if (size <= 0)
                _szIdx = 0;
            else
            _szIdx = size - 1;
            _currentSize = _sizes[_szIdx];
            _sizeSelStarted = false;
            ShowButtons("sz", false);
            ExecResizeSelection();
        }

        /// <summary>
        /// Creates context menu for selected objects
        /// </summary>
        private void CreateContextMenu()
        {
            if (null == _canvasMenu)
            {
                _canvasMenu = new ContextMenu();
                var delPt = new MenuItem { Header = "Delete" };
                var icon = new Image();
                var img = new BitmapImage();
                img.BeginInit();
                img.UriSource = new Uri("Resources/del.png", UriKind.Relative);
                img.EndInit();
                icon.Source = img;
                icon.MaxWidth = 16;
                delPt.Icon = icon;
                delPt.Click += DelItem_Clicked;
                _canvasMenu.Items.Add(delPt);
                Drawbot.Menu = _canvasMenu;
            }
        }

        /// <summary>
        /// Reset all states like we just loaded our app
        /// </summary>
        private void ResetAndPrepareApp()
        {
            if (null == Drawbot)
            {
                Draw.Children.Clear();
                Drawbot = new drawingMachine(Draw);
            }

            _nowSelectedTool = eCurSel.DrawPoint;
            _lastMode = _nowSelectedMode = _nowSelectedTool;
            _pts = new List<Point>();

            if (null == _sizes)
                _sizes = new List<byte> { 6, 12, 18, 24, 30 };
            _currentColor = Colors.Black;
            LblForeColor.Background = new SolidColorBrush(_currentColor);
            _backgroundColor = Colors.WhiteSmoke;
            LblBackColor.Background = new SolidColorBrush(_backgroundColor);
            Draw.Background = LblBackColor.Background;
            ImgPal.Visibility = Visibility.Hidden;
            _isPalVisible = false;
            _palSelection = false;
            PalRect.Visibility = Visibility.Hidden;
            _sizeSelStarted = false;
            _toolSelStarted = false;
            _isBackColor = false;
            _selectionColor = weBoardRoutines.GetMedInvColor(_backgroundColor, _currentColor);

            ImgConnectionState.Source = weBoardRoutines.GetImage("Resources/conn_down.png");
            ImgConnectionState.ToolTip = "Disconnected";

            SetSize(3);
            ShowButtons("sz", false);
            ShowButtons("tool", false);
            Deselect();
            ResetDrawingState();          
            CreateContextMenu();
            InitImages();
            SetMode(_nowSelectedMode);
            ImgSelect.Source = _modeMedia[(int)eCurSel.Select].InactiveBmp;

            Draw.Cursor = _modeMedia[(int) _nowSelectedTool].Cursor;
            ImgNow.Source = _modeMedia[(int) _nowSelectedTool].ActiveBmp;

            if (CheckDefPort.IsChecked != null && CheckDefPort.IsChecked.Value)
                TxtPortNum.IsEnabled = false;
        }

        /// <summary>
        /// Sets selected mode and performs some dependent work
        /// </summary>
        /// <param name="mode">Mode to set</param>
        private void SetMode(eCurSel mode)
        {
            if (mode == eCurSel.Select)
                return;

            _lastMode = _nowSelectedMode = _nowSelectedTool = mode;
            Draw.Cursor = _modeMedia[(int)_nowSelectedTool].Cursor;
            ImgNow.Source = _modeMedia[(int)_nowSelectedTool].ActiveBmp;
        }

        /// <summary>
        /// Sets new colors based on a color of a given Label
        /// </summary>
        /// <param name="lbl">Label to process</param>
        private void ProcessLabelColors(Label lbl)
        {
            if (_isBackColor)
            {
                _backgroundColor = ((SolidColorBrush)lbl.Background).Color;
                _selectionColor = weBoardRoutines.GetMedInvColor(_backgroundColor, _currentColor);
                LblBackColor.Background = lbl.Background;
                Draw.Background = lbl.Background;
                Drawbot.Reselect(_selectionColor);
            }
            else
            {
                _currentColor = ((SolidColorBrush)lbl.Background).Color;
                LblForeColor.Background = lbl.Background;
                ExecSetObjectColors();
            }
        }

        /// <summary>
        /// Does some dirty work like enable/disable some controls
        /// </summary>
        private int ProcessNetworkControls(bool state)
        {
            TxtHostname.IsEnabled = !state;
            BtnDiscover.IsEnabled = !state;
            CheckDefPort.IsEnabled = !state;
            TxtNickname.IsEnabled = !state;
            BtnConnect.Content = state ? "DISCONNECT" : "CONNECT";
            Title = state
                ? "weBoard::Online at@" + TxtHostname.Text + " as " + TxtNickname.Text
                : "weBoard::Offline";
            if (CheckDefPort.IsChecked == true)
                checkDefPort_Checked(CheckDefPort, new RoutedEventArgs());
            else
            {
                checkDefPort_Unchecked(CheckDefPort, new RoutedEventArgs());
                TxtPortNum.IsEnabled = !state;
            }
            if (state)
            {
                ImgConnectionState.Source = weBoardRoutines.GetImage("Resources/conn_up.png");
                ImgConnectionState.ToolTip = "Connected";
            }
            else
            {
                ImgConnectionState.Source = weBoardRoutines.GetImage("Resources/conn_down.png");
                ImgConnectionState.ToolTip = "Disconnected";
            }
            return 0;
        }

        /// <summary>
        /// Connect with weBoardServer
        /// </summary>
        private void DoConnect()
        {
            try
            {
                if (_client == null)
                    _client = new weBoardClient();
                if (_client.Connected)
                    _client.Disconnect();
                else
                    _client.Connect(TxtNickname.Text, TxtHostname.Text, Convert.ToInt32(TxtPortNum.Text),
                                ProcessNetworkControls, this);
                Thread.Sleep(50);
                ProcessNetworkControls(_client.Connected);
                if (_client.Connected)
                {
                    if (Drawbot.GetActionsCount > 0)
                        if (MessageBox.Show("Dow you wish to save your offline drawing?", "Collaboration prepare action", MessageBoxButton.YesNo,
                            MessageBoxImage.Question) == MessageBoxResult.Yes)
                            BtnSave_Click(this, new RoutedEventArgs());
                    Drawbot.Clear();
                }
            }
            catch (FormatException ex)
            {
                MessageBox.Show(ex.Message, "Failed to connect");
            }
            catch (ArgumentOutOfRangeException ex)
            {
                MessageBox.Show(ex.Message, "Failed to connect");
            }
            catch (Exception ex)
            {
                if (_client != null)
                    _client.Disconnect();
                MessageBox.Show(ex.Message, "Failed to connect");
                ProcessNetworkControls(false);
            }
        }
        
        /// <summary>
        /// This for gui connected with start/stop server discover action
        /// </summary>
        /// <param name="enable"></param>
        private void SetDiscoverControls(bool enable)
        {
            TxtHostname.IsEnabled = enable;
            CheckDefPort.IsEnabled = enable;
            TxtNickname.IsEnabled = enable;
            BtnConnect.IsEnabled = enable;
            if (CheckDefPort.IsChecked == true)
                checkDefPort_Checked(CheckDefPort, new RoutedEventArgs());
            else
            {
                checkDefPort_Unchecked(CheckDefPort, new RoutedEventArgs());
                TxtPortNum.IsEnabled = enable;
            }
        }

        /// <summary>
        /// Seeking local net area to discover 1st alive weBoardServer
        /// </summary>
        private void ThreadedDiscover()
        {
            var ip = weBoardRoutines.GetLocalIp();
            var port = 0;
            Application.Current.Dispatcher.Invoke(new Action(() =>
            {
                port = Convert.ToInt32(TxtPortNum.Text);
            }));
            weBoardClient discoverClient = null;
            for (var idx = 1; idx < 255; idx++)
            {
                GC.Collect();
                var stop = false;
                Application.Current.Dispatcher.Invoke(new Action(() =>
                {
                    stop = !_discovering;
                }));
                if (stop)
                {
                    if (discoverClient != null)
                        if (discoverClient.GetThread != null)
                            discoverClient.GetThread.Abort();
                    return;
                }
                discoverClient = new weBoardClient();
                var varIp = ip;
                varIp = varIp.Remove(varIp.LastIndexOf('.') + 1);
                varIp += idx;
                discoverClient.Connect("#SEARCH", varIp, port, ProcessNetworkControls, this);
                Thread.Sleep(200);
                if (!discoverClient.WasConnected)
                    continue;
                if (discoverClient.Discovered)
                {
                    discoverClient.Disconnect();
                    Application.Current.Dispatcher.Invoke(new Action(() =>
                    {
                        SetDiscoverControls(true);
                        TxtHostname.Text = varIp;
                        TxtHostname.Focus();
                        TxtHostname.SelectAll();
                        _discovering = false;
                    }));
                    break;
                }
                discoverClient.Disconnect();
            }
        }
        #endregion Additional GUI logic to reduce functions' sizes and code dups

        #region Event handlers
        //-----------------------------------------------------------------
        //Event handlers below
        //-----------------------------------------------------------------

        /// <summary>
        /// The window was loaded so we need to make some preparations
        /// </summary>
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            ResetAndPrepareApp();
        }

        /// <summary>
        /// Context menu's "Delete" item was clicked
        /// </summary>
        private void DelItem_Clicked(object sender, RoutedEventArgs e)
        {
            ExecDeleteSelected();
            _nowSelectedMode = _lastMode;
            if (_nowSelectedMode == eCurSel.Select)
            {
                BtnSelect_Click(sender, e);
                BtnSelect.Focus();
            }
            else
            {
                SetMode(_nowSelectedMode);
                ImgSelect.Source = _modeMedia[(int) eCurSel.Select].InactiveBmp;
                BtnTool.Focus();
            }
            e.Handled = true;
        }

        /// <summary>
        /// The window was closed so we've got some actions to be done
        /// </summary>
        private void Window_Closed(object sender, EventArgs e)
        {
            Settings.Default.Save();
        }

        /// <summary>
        /// We've selected default port
        /// </summary>
        private void checkDefPort_Checked(object sender, RoutedEventArgs e)
        {
            TxtPortNum.Text = Settings.Default["DefaultPortNum"].ToString();
            TxtPortNum.IsEnabled = false;
        }

        /// <summary>
        /// We've selected custom port
        /// </summary>
        private void checkDefPort_Unchecked(object sender, RoutedEventArgs e)
        {
            TxtPortNum.IsEnabled = true;
        }

        /// <summary>
        /// We've started creation or selection
        /// </summary>
        private void Draw_MouseDown(object sender, MouseButtonEventArgs e)
        {
            HideTools();
            _creation = false;
            _position = new Point(e.GetPosition(Draw).X, e.GetPosition(Draw).Y);
            DrawCoords();
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                Deselect();
                _canMove = true;
                Drawbot.CanRaiseUp = false;
                _firstMove = 1;
                if (_nowSelectedMode != eCurSel.Select)
                {
                    if (_nowSelectedMode == eCurSel.DrawPoint)
                        ExecPointCreation();
                    else
                        Exec2PtObjectsCreation(_nowSelectedMode);
                    _creation = true;
                }
                else
                {
                    Select();
                    Drawbot.SetDelta(_position, true);
                }
            }
            if (e.RightButton == MouseButtonState.Pressed)
            {
                _firstMove = 0;
                Deselect();
                if (Select())
                {
                    var tmp = _lastMode;
                    BtnSelect_Click(sender, e);
                    _lastMode = tmp;
                    Drawbot.SetDelta(_position, true);
                    Drawbot.Menu.IsOpen = true;
                }
            }
        }

        /// <summary>
        /// Tracks mouse moves at drawing canvas
        /// </summary>
        private void Draw_MouseMove(object sender, MouseEventArgs e)
        {
            _position = new Point(e.GetPosition(Draw).X, e.GetPosition(Draw).Y);
            DrawCoords();
            if (e.LeftButton == MouseButtonState.Pressed && _canMove)
            {
                if (_firstMove > 0)
                    _firstMove++;
                if (_creation && _firstMove == 3)
                {
                    Select();
                    Drawbot.SetDelta(_position, true);
                }
                if (_firstMove == 3)
                    Drawbot.RememberOldPos();
                if (_firstMove == 4)
                {
                    _firstMove = 0;
                    Drawbot.CanRaiseUp = true;
                }
                ExecMoveSelectionObjects(false);
            }
        }

        /// <summary>
        /// We've finished smth
        /// </summary>
        private void Draw_MouseUp(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
            if (Drawbot.CanRaiseUp)
            {
                Drawbot.CanRaiseUp = false;
                ExecMoveSelectionObjects(true);
                if (_nowSelectedMode != eCurSel.Select)
                    Deselect();
            }
        }

        /// <summary>
        /// Tracks leaving of mouse from drawing canvas area
        /// </summary>
        private void Draw_MouseLeave(object sender, MouseEventArgs e)
        {
            ResetDrawingState();
        }

        /// <summary>
        /// We wanna save the picture
        /// </summary>
        private void BtnSave_Click(object sender, RoutedEventArgs e)
        {
            HideTools();
            var dialog = new SaveFileDialog
            {
                DefaultExt = ".png",
                FileName = "drawing.png",
                Filter = "PNG image files (*.png)|*.png|" +
                         "weBoard macro files (*.weboard)|*.weboard|" +
                         "weBoard compressed macro files (*.weboardz)|*.weboardz",
                FilterIndex = 1,
                AddExtension = true,
                RestoreDirectory = true,
            };
            var result = dialog.ShowDialog();
            if (result == true)
            {
                switch (dialog.FilterIndex)
                {
                    case 1:
                        SaveCanvas(Draw, dialog.FileName);
                        break;
                    case 2:
                        Drawbot.Save(dialog.FileName, true);
                        break;
                    case 3:
                        Drawbot.Save(dialog.FileName, false);
                        break;
                }
            }
        }

        /// <summary>
        /// We'd like to redo last action
        /// </summary>
        private void BtnRedo_Click(object sender, RoutedEventArgs e)
        {
            HideTools();
            Redo();
        }

        /// <summary>
        /// We'd like to undo last action
        /// </summary>
        private void BtnUndo_Click(object sender, RoutedEventArgs e)
        {
            HideTools();
            Undo();
        }

        /// <summary>
        /// We'd like to change a size of an object
        /// </summary>
        private void BtnSize_Click(object sender, RoutedEventArgs e)
        {
            if (_isPalVisible)
                BtnPalette_Click(sender, e);
            if (_toolSelStarted)
                BtnTool_Click(sender, e);
            _sizeSelStarted = !_sizeSelStarted;
            ShowButtons("sz", _sizeSelStarted);
        }

        /// <summary>
        /// We'd like to select color via extended palette
        /// </summary>
        private void BtnPalette_Click(object sender, RoutedEventArgs e)
        {
            if (_sizeSelStarted)
                BtnSize_Click(sender, e);
            if (_toolSelStarted)
                BtnTool_Click(sender, e);
            ImgPal.Visibility = !_isPalVisible ? Visibility.Visible : Visibility.Hidden;
            _isPalVisible = !_isPalVisible;
        }

        /// <summary>
        /// We'd like to draw a point
        /// </summary>
        private void BtnTool_Click(object sender, RoutedEventArgs e)
        {
            if (_sizeSelStarted)
                BtnSize_Click(sender, e);
            if (_isPalVisible)
                BtnPalette_Click(sender, e);
            _toolSelStarted = !_toolSelStarted;
            ShowButtons("tool", _toolSelStarted);
            _lastMode = _nowSelectedMode = _nowSelectedTool;

            Draw.Cursor = _modeMedia[(int) _nowSelectedTool].Cursor;
            ImgNow.Source = _modeMedia[(int) _nowSelectedTool].ActiveBmp;

            ImgSelect.Source = _modeMedia[(int)eCurSel.Select].InactiveBmp;
        }

        /// <summary>
        /// We'd like to select an object
        /// </summary>
        private void BtnSelect_Click(object sender, RoutedEventArgs e)
        {
            HideTools();
            _lastMode = _nowSelectedMode = eCurSel.Select;
            Draw.Cursor = _modeMedia[(int) eCurSel.Select].Cursor;
            ImgSelect.Source = _modeMedia[(int)eCurSel.Select].ActiveBmp;
            ImgNow.Source = _modeMedia[(int) _nowSelectedTool].InactiveBmp;
        }

        /// <summary>
        /// We'd like to send some command via kbd
        /// </summary>
        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            ProcessKeyboard(e);
        }

        /// <summary>
        /// We wanna change destination of future selected colors to objects
        /// </summary>
        private void lblForeColor_MouseDown(object sender, MouseButtonEventArgs e)
        {
            _isBackColor = false;
            Panel.SetZIndex(LblForeColor, 2);
            Panel.SetZIndex(LblBackColor, 1);
            _currentColor = ((SolidColorBrush)LblForeColor.Background).Color;
            ExecSetObjectColors();
        }

        /// <summary>
        /// We wanna change destination of future selected colors to background
        /// </summary>
        private void lblBackColor_MouseDown(object sender, MouseButtonEventArgs e)
        {
            _isBackColor = true;
            Panel.SetZIndex(LblForeColor, 1);
            Panel.SetZIndex(LblBackColor, 2);
            _backgroundColor = ((SolidColorBrush)LblBackColor.Background).Color;
            _selectionColor = weBoardRoutines.GetMedInvColor(_backgroundColor, _currentColor);
            Draw.Background = LblBackColor.Background;
        }

        /// <summary>
        /// We made a decision about color via ImgPalette
        /// </summary>
        private void imgPalette_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            SetNewColors(ImgPalette, true);
        }

        /// <summary>
        /// We are selecting color right now via ImgPalette
        /// </summary>
        private void imgPalette_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
                SetNewColors(ImgPalette, false);
        }

        /// <summary>
        /// Setting size 1
        /// </summary>
        private void btnSz1_Click(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            SetSize(1);
        }

        /// <summary>
        /// Setting size 2
        /// </summary>
        private void btnSz2_Click(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            SetSize(2);
        }

        /// <summary>
        /// Setting size 3
        /// </summary>
        private void btnSz3_Click(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            SetSize(3);
        }

        /// <summary>
        /// Setting size 4
        /// </summary>
        private void btnSz4_Click(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            SetSize(4);
        }

        /// <summary>
        /// Setting size 5
        /// </summary>
        private void btnSz5_Click(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            SetSize(5);
        }

        /// <summary>
        /// We made a decision about color via ImgPal
        /// </summary>
        private void imgPal_MouseDown(object sender, MouseButtonEventArgs e)
        {   
            if (_palSelection)
            {
                SetNewColors(ImgPal, true);
                ExecSetObjectColors();
                _palSelection = false;
            }
            BtnPalette_Click(this, new RoutedEventArgs());
        }

        /// <summary>
        /// We are selecting color right now via ImgPal
        /// </summary>
        private void imgPal_MouseMove(object sender, MouseEventArgs e)
        {
           _palSelection = true;
           var x = (int)Mouse.GetPosition(ImgPal).X;
           var y = (int)Mouse.GetPosition(ImgPal).Y;
           PalRect.Margin = new Thickness(50 + x, 130 + y, 0, 0);
           _tmpPalColor = weBoardRoutines.GetColorAtMousePoint(ImgPal);
           PalRect.Fill = new SolidColorBrush(_tmpPalColor);
        }

        /// <summary>
        /// Mouse has entered ImgPal area so wee should show our helper rect
        /// </summary>
        private void imgPal_MouseEnter(object sender, MouseEventArgs e)
        {
            PalRect.Visibility = Visibility.Visible;
        }

        /// <summary>
        /// Mouse has leaved ImgPal area so wee should hide our helper rect
        /// </summary>
        private void imgPal_MouseLeave(object sender, MouseEventArgs e)
        {
            PalRect.Visibility = Visibility.Hidden;
        }

        /// <summary>
        /// We made a decision about color via ImgPalette
        /// </summary>
        private void ImgPalette_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            SetNewColors(ImgPalette, true);
            ExecSetObjectColors();
        }

        /// <summary>
        /// We've selected "Line" tool
        /// </summary>
        private void btnLine_Click(object sender, RoutedEventArgs e)
        {
            SetMode(eCurSel.DrawLine);
            HideTools();
        }

        /// <summary>
        /// We've selected "Rectangle" tool
        /// </summary>
        private void btnRectangle_Click(object sender, RoutedEventArgs e)
        {
            SetMode(eCurSel.DrawRect);
            HideTools();
        }

        /// <summary>
        /// We've selected "Ellipse" tool
        /// </summary>
        private void btnEllipse_Click(object sender, RoutedEventArgs e)
        {
            SetMode(eCurSel.DrawEllipse);
            HideTools();
        }

        /// <summary>
        /// We've selected "Polygon" tool
        /// </summary>
        private void btnPolygon_Click(object sender, RoutedEventArgs e)
        {
            SetMode(eCurSel.DrawPolygon);
            HideTools();
        }

        /// <summary>
        /// We've selected "Path" tool
        /// </summary>
        private void btnPath_Click(object sender, RoutedEventArgs e)
        {
            SetMode(eCurSel.DrawPath);
            HideTools();
        }

        /// <summary>
        /// We've selected "Polyline" tool
        /// </summary>
        private void btnPolyline_Click(object sender, RoutedEventArgs e)
        {
            SetMode(eCurSel.DrawPolyline);
            HideTools();
        }

        /// <summary>
        /// We've selected "Point" tool
        /// </summary>
        private void btnPoint_Click(object sender, RoutedEventArgs e)
        {
            SetMode(eCurSel.DrawPoint);
            HideTools();
        }

        /// <summary>
        /// We'd like to open smth.
        /// </summary>
        private void btnOpen_Click(object sender, RoutedEventArgs e)
        {
            HideTools();
            var dialog = new OpenFileDialog
            {
                DefaultExt = ".weboard",
                AddExtension = true,
                Filter = "weBoard macro files (*.weboard)|*.weboard|weBoard compressed macro files (*.weboardz)|*.weboardz",
                FilterIndex = 1,
                RestoreDirectory = true,
            };
            var result = dialog.ShowDialog();
            if (result == true)
            {
                try
                {
                    switch (dialog.FilterIndex)
                    {
                        case 1:
                            Drawbot.Open(dialog.FileName, true);
                            break;
                        case 2:
                            Drawbot.Open(dialog.FileName, false);
                            break;
                    }
                    ResetAndPrepareApp();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "Error occured while opening macro!", 
                        MessageBoxButton.OK, MessageBoxImage.Error);
                }
            } 
        }

        /// <summary>
        /// Select this color
        /// </summary>
        private void rectL1_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            ProcessLabelColors(RectL1);
        }

        /// <summary>
        /// Select this color
        /// </summary>
        private void rectL2_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            ProcessLabelColors(RectL2);
        }

        /// <summary>
        /// Select this color
        /// </summary>
        private void rectL3_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            ProcessLabelColors(RectL3);
        }

        /// <summary>
        /// Select this color
        /// </summary>
        private void rectL4_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            ProcessLabelColors(RectL4);
        }

        /// <summary>
        /// Select this color
        /// </summary>
        private void rectL5_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            ProcessLabelColors(RectL5);
        }

        /// <summary>
        /// We'd like to connect or disconnect
        /// </summary>
        private void btnConnect_Click(object sender, RoutedEventArgs e)
        {
            DoConnect();
        }

        /// <summary>
        /// We'd like to discover server in our local network
        /// </summary>
        private void btnDiscover_Click(object sender, RoutedEventArgs e)
        {
            _discThread = new Thread(ThreadedDiscover);
            _discovering = !_discovering;
            SetDiscoverControls(!_discovering);
            if (!_discovering)
            {
                SetDiscoverControls(true);
                return;
            }
            try
            {
                _discThread.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Discover::Failed", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                _discovering = false;
               SetDiscoverControls(true);
            }
        }

        /// <summary>
        /// Close handles, end threads ets
        /// </summary>
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (_client != null)
                if (_client.Connected)
                    _client.Disconnect();
            e.Cancel = false;
        }

        /// <summary>
        /// Second way to connect
        /// </summary>
        private void TxtNickname_KeyDown(object sender, KeyEventArgs kbd)
        {
            if (kbd.Key == Key.Enter)
                DoConnect();
        }
        #endregion Event handlers
    }
}
